package chatroom.fq.ley;
import java.io.*;
import java.lang.reflect.Array;
import java.net.*;
import java.util.*;
import chatroom.fq.ley.peer;
/* ---------------------------------------------------
 * The server entry;
 * Lei Peng, 2012-10;
 * ---------------------------------------------------*/
class server {
	private String name;	//Server name;
	private String welStr;	//Welcome information;
	private DatagramSocket st;
	private int peerMax;	//Maximum peers;
	private int bufMax;	//Maximum buffer size;
	private int port;	//Running port;
	private String enterFlag;	//Enter flag which is contained by name;
	peer peers[]; //Peers & subscribers;
	private int np;	//Number of peers online;
	private String message(String header,String msgNum,String msgType,String msgStr){
		return header+":"+msgNum+":"+this.name+":Chatroom:"+msgType+":"+msgStr;
	}
	public server(String cfgPath){
		this.init(cfgPath);
	}
	//initialize with a certain configuration;
	public int init(String cfgPath){	
		try{
			FileInputStream fin=new FileInputStream(cfgPath);
			Properties props=new Properties();
			props.load(fin);
			fin.close();
			this.port=Integer.parseInt(props.getProperty("PORT"));
			this.name=props.getProperty("NAME");
			this.peerMax=Integer.parseInt(props.getProperty("PEER_MAX"));
			this.bufMax=Integer.parseInt(props.getProperty("BUFFER_MAX"));
			this.enterFlag=props.getProperty("ENTER_FLAG");
			this.welStr=props.getProperty("WELCOME_INFO");
			this.st=new DatagramSocket(this.port);
			return 0;
		}
		catch(Exception e){
			return -1;
		}
	}
	public String getName(){
		return this.name;
	}
	public int getPeerMax(){
		return this.peerMax;
	}
	public DatagramSocket getSocket(){
		return this.st;
	}
	public void log(String str){
		Date now=new Date();
		System.out.println("["+now.toString()+"]"+str);
	}
	public int send(String ip,int port,String buf){
		try{
			this.st.send(new DatagramPacket(buf.getBytes(),buf.length(),InetAddress.getByName(ip),port));
			return 0;
		}
		catch(Exception e){
			e.printStackTrace();
			return -1;
		}
	}
	public int sendAll(String str){
		for(int i=0;null!=this.peers[i];i++){
			if(-1==this.send(this.peers[i].ip, this.peers[i].port, str))
				return -1;
		}
		return 0;
	}
	public String command(String cmd[]){
		String cmd1=((cmd[0].toUpperCase()).substring(1)).trim();
		if(0==cmd1.compareTo("WHO")){
			//Show online users;
			StringBuffer rt=new StringBuffer("Online users:");
			for(int i=0;null!=this.peers[i];i++)
				rt.append(this.peers[i].name+" ");
			return rt.toString();
		}
		if(0==cmd1.compareTo("INFO")){
			if(2!=Array.getLength(cmd)){
				return new String("Usage: info user@group");
			}
			for(int i=0;null!=this.peers[i];i++){
				if(0==(cmd[1].trim()).compareTo(this.peers[i].name)){
					return new String("Name:"+this.peers[i].name+"\nIP:"+this.peers[i].ip+"\nPort:"+this.peers[i].port);
				}
			}
			return new String("No such user online.");
		}
		if(0==cmd1.compareTo("HELP")){
			//Show usage;
			String rt="FeiQ Chatroom v 0.0.1.\n#who - Show online users;\n#info user@group - Show info of a user;\n#help - Show usage;";
			return rt;
		}
		return new String("Unknow command;");
	}
	public void run(){
		String fh="1_lbt4_0#131#001E37563998#2139#0#0";
		this.peers=new peer[this.peerMax];
		this.np=0;	//Current number of online peers;
		try{
			this.log(this.name+" Running at "+this.port+"........");
			while(true){
				byte[] buf=new byte[this.bufMax];
				DatagramPacket dp=new DatagramPacket(buf,this.bufMax);
				st.receive(dp);
				String bufs[]=(new String(buf)).split(":");
				switch(Integer.parseInt(bufs[4])){
				case 0:
					//Send online state;
					if(-1==this.send(dp.getAddress().getHostAddress(), this.port, this.message(fh, "100", "1", this.name)))
						this.log("Send Message failed.");
					break;
				case 1:
				case 6291457:	//Compatible for FeiQ;
				case 6291459:
					//Send online state;
					int msgType=Integer.parseInt(bufs[4]);
					if(6291457==msgType)
						if(-1==this.send(dp.getAddress().getHostAddress(), this.port, this.message(fh, "100", "6291457", this.name)))
							this.log("Send Message failed.");
	
					//Add new user to peer list;
					int has=0;
					String nameIn=null;
					for(int i=0;null!=peers[i];i++){
						if(this.peers[i].toString().equals(dp.getAddress().getHostAddress()+":"+dp.getPort())){
							has=1;
							break;
						}
					}
					if(0==has && this.np<this.peerMax && -1!=bufs[5].indexOf(this.enterFlag)){
						byte name[]=bufs[5].getBytes();
						name[bufs[5].indexOf('\0')]='@';
						String nameto=new String(name).replace('\0', ' ');
						nameIn=new String(nameto.trim());
						peers[this.np]=new peer(dp.getAddress().getHostAddress(),dp.getPort(),nameIn);
						this.np+=1;
					}
					//Send welcome message;
					if(null!=nameIn){
							this.sendAll(this.message(fh,"100","32",nameIn+" has been join the chatroom."));
							//Send welcome message;
							this.send(dp.getAddress().getHostAddress(), dp.getPort(), this.message(fh, "100", "32", this.welStr));
					}
					//Show online users;
					this.log("(+)Users:"+this.np);
					for(int i=0;null!=this.peers[i];i++){
						this.log(bufs[4]+">"+peers[i].name+"@"+peers[i].toString());
					}
					break;
				case 2:
				case 6291458:	//FeiQ command;
					//Off line;
					int bp=0;	//break point;
					String nameOff=null;
					for(int i=0;null!=this.peers[i];i++){
						if(0==this.peers[i].toString().compareTo(dp.getAddress().getHostAddress()+":"+dp.getPort())){
							bp=i;
							nameOff=peers[i].name;
							break;
						}
					}
					for(int i=bp;null!=peers[i+1];i++){
						bp=i;
						peers[i]=peers[i+1];
					}
					//Send bye message;
					if(null!=nameOff){
						peers[bp]=null;
						this.np-=1;
							this.sendAll(this.message(fh,"100","32",nameOff+" has been left the chatroom."));
					}
					//Show online users;
					this.log("(-)Users:"+this.np);
					for(int i=0;null!=this.peers[i];i++){
						this.log(peers[i].name+"@"+peers[i].toString());
					}
					break;
				case 122:
					if(-1==this.send(dp.getAddress().getHostAddress(), this.port, fh+":100:"+this.name+":Chatroom:122:"))
						this.log("Send Message failed.");
					break;
				case 32:
				case 288: //FeiQ compatible;
					//Send 'received'(33) command;
					if(-1==this.send(dp.getAddress().getHostAddress(), this.port, this.message(fh,"100","33",bufs[1])))
						this.log("Send Message failed.");
					//Message;
					String name = null;
					for(int i=0;null!=peers[i];i++){
						if(peers[i].ip.equals(dp.getAddress().getHostAddress())){
							name=peers[i].name;
							break;
						}
					}
					if(null!=name){
						//Command operation;
						if(0==bufs[5].indexOf('#')){
							String cmd[]=bufs[5].split(" ");
							String rst=this.command(cmd);
							this.send(dp.getAddress().getHostAddress(), dp.getPort(), this.message(fh,"100","32",rst));
						}else{
							//Normal message;
							for(int i=0;null!=peers[i];i++){
								if(!peers[i].ip.equals(dp.getAddress().getHostAddress()))
									if(-1==this.send(peers[i].ip, peers[i].port, this.message(fh,"100","32",name+">"+bufs[5])))
										this.log("Send Message failed.");
							}
						}
					}
					break;
				case 33:
					//Ignore message received;
				case 121:
					//Ignore key input message;
				case 119:
				case 123:
				case 193:	//FeiQ Picture sending;
				case 2097344: //FeiQ picture sending;
					break;
				default:
					//this.log(dp.getAddress().toString()+">"+(new String(buf)));
					break;
				}
			}
		}
		catch(Exception e){
			e.printStackTrace();
		}
	}
}
